﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.StackExchangeRedis;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using StarUtils.Extension;
using StarUtils.Cache;

namespace StarUtils.Cache
{
    public static class Extensions
    {
        public static void ConfigureServices(this IServiceCollection services)
        {
            services.AddOptions();
            string[] array = DbConnetStringFrom.GetRedisConfig("Default:Master:Add:host")?.Split(':');
            string host = "192.168.0.23";
            int port = 6379;
            string dbName = "DefaultRedis10";
            if (array != null && array.Length == 2)
            {
                host = array[0];
                int.TryParse(array[1], out port);
            }

            services.Configure(dbName, delegate (RedisOptions x)
            {
                x.DbConfig.Database = 10;
                x.PrefixName = "session:";
                x.DbConfig.AllowAdmin = true;
                x.DbConfig.EndPoints.Add(new ServerEndPoint
                {
                    Host = host,
                    Port = port
                });
            });
            services.AddSingleton<IRedisDatabaseProvider, RedisDatabaseProvider>(delegate (IServiceProvider x)
            {
                RedisOptions options = x.GetRequiredService<IOptionsMonitor<RedisOptions>>().Get(dbName);
                return new RedisDatabaseProvider(dbName, options);
            });
            IRedisDatabaseProvider dbProvider;
            services.AddSingleton<IDistributedCache, RedisCacheForSession>(delegate (IServiceProvider p)
            {
                dbProvider = p.GetServices<IRedisDatabaseProvider>().FirstOrDefault((IRedisDatabaseProvider x) => !x.DbProviderName.IsNull() && x.DbProviderName.Equals(dbName));
                IOptionsMonitor<RedisOptions> requiredService = p.GetRequiredService<IOptionsMonitor<RedisOptions>>();
                services.AddDataProtection().PersistKeysToStackExchangeRedis(dbProvider.GetConnectionMultiplexer(), "datapro");
                services.AddStackExchangeRedisCache(delegate (Microsoft.Extensions.Caching.StackExchangeRedis.RedisCacheOptions o)
                {
                    o.Configuration = $"{host}:{port}";
                    o.ConfigurationOptions = new ConfigurationOptions
                    {
                        DefaultDatabase = 10,
                        ConnectTimeout = 5000
                    };
                    o.InstanceName = "rediscache:";
                });
                return new RedisCacheForSession(dbProvider, requiredService);
            });
        }

        public static void AddSessionWithRedis(this IServiceCollection services, RedisOptions redisOptions = null)
        {
            services.AddOptions();
            string text = string.Empty;
            int result = 0;
            _ = string.Empty;
            int num = 10;
            if (redisOptions == null)
            {
                string[] array = DbConnetStringFrom.GetRedisConfig("Default:Master:Add:host")?.Split(':');
                if (array != null && array.Length == 2)
                {
                    text = array[0];
                    int.TryParse(array[1], out result);
                }
            }
            else
            {
                text = redisOptions.DbConfig.EndPoints[0].Host;
                result = redisOptions.DbConfig.EndPoints[0].Port;
                num = redisOptions.DbConfig.Database;
            }

            if (text.IsNullOrEmpty())
            {
                throw new ArgumentNullException("host");
            }

            _ = "DefaultRedis" + num;
            string redisConnStr = $"{text}:{result},allowAdmin=true,defaultdatabase={num}";
            services.AddDataProtection().SetApplicationName(Assembly.GetExecutingAssembly().FullName).PersistKeysToStackExchangeRedis(ConnectionMultiplexer.Connect(redisConnStr), "DataProtection-Keys");
            services.AddStackExchangeRedisCache(delegate (Microsoft.Extensions.Caching.StackExchangeRedis.RedisCacheOptions options)
            {
                options.Configuration = redisConnStr;
            });
            services.AddSession(delegate (SessionOptions options)
            {
                options.Cookie.Name = "data_protection";
                options.IdleTimeout = TimeSpan.FromMinutes(60.0);
                options.Cookie.HttpOnly = true;
                options.Cookie.IsEssential = true;
            });
        }

        public static void AddDefaultRedisCacheWithFactory(this IServiceCollection services, string name, RedisOptions redisOptions)
        {
            services.AddOptions();
            services.Configure(name, delegate (RedisOptions x)
            {
                if (!redisOptions.DbConfig.Configuration.IsNullOrWhiteSpace())
                {
                    x.DbConfig.Configuration = redisOptions.DbConfig.Configuration;
                }
                else
                {
                    x.DbConfig.Database = redisOptions.DbConfig.Database;
                    x.PrefixName = redisOptions.PrefixName;
                    x.DbConfig.AllowAdmin = redisOptions.DbConfig.AllowAdmin;
                    x.DbConfig.Password = redisOptions.DbConfig.Password;
                    x.DbConfig.IsSsl = redisOptions.DbConfig.IsSsl;
                    x.DbConfig.SslHost = redisOptions.DbConfig.SslHost;
                    x.DbConfig.ConnectionTimeout = redisOptions.DbConfig.ConnectionTimeout;
                    if (redisOptions.DbConfig.EndPoints == null || redisOptions.DbConfig.EndPoints.Count == 0)
                    {
                        string[] array = DbConnetStringFrom.GetRedisConfig("Default:Master:Add:host")?.Split(':');
                        string host = "127.0.0.1";
                        int result = 6379;
                        if (array != null && array.Length == 2)
                        {
                            host = array[0];
                            int.TryParse(array[1], out result);
                        }

                        x.DbConfig.EndPoints.Add(new ServerEndPoint
                        {
                            Host = host,
                            Port = result
                        });
                    }
                    else
                    {
                        redisOptions.DbConfig.EndPoints.ForEach(delegate (ServerEndPoint p)
                        {
                            x.DbConfig.EndPoints.Add(p);
                        });
                    }
                }
            });
            services.AddSingleton<ICacheProiderFactory, DefaultCacheProviderFactory>();
            services.TryAddSingleton<ICacheSerializer, TextJsonFormaterSerializer>();
            services.AddSingleton<IRedisDatabaseProvider, RedisDatabaseProvider>(delegate (IServiceProvider x)
            {
                RedisOptions options = x.GetRequiredService<IOptionsMonitor<RedisOptions>>().Get(name);
                return new RedisDatabaseProvider(name, options);
            });
            services.AddSingleton<ICacheProvider, RedisCacheProvider>(delegate (IServiceProvider x)
            {
                IEnumerable<IRedisDatabaseProvider> services2 = x.GetServices<IRedisDatabaseProvider>();
                ICacheSerializer requiredService = x.GetRequiredService<ICacheSerializer>();
                IOptionsMonitor<RedisOptions> requiredService2 = x.GetRequiredService<IOptionsMonitor<RedisOptions>>();
                return new RedisCacheProvider(name, services2, requiredService, requiredService2);
            });
        }
    }
}
